package com.bsj.power.pls.service.impl;

import cn.hutool.http.HttpUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.bsj.power.common.config.cached.*;
import com.bsj.power.common.config.exception.ApiException;
import com.bsj.power.common.config.global.JsonResult;
import com.bsj.power.common.config.global.JsonResultEnum;
import com.bsj.power.common.config.redis.RedisConstant;
import com.bsj.power.common.constant.ApiConstants;
import com.bsj.power.common.constant.NumericalConstants;
import com.bsj.power.common.constant.UWBPosConstant;
import com.bsj.power.common.def.dto.DeleteDTO;
import com.bsj.power.common.def.dto.TrackDTO;
import com.bsj.power.common.def.dto.cardReport.BindCardDTO;
import com.bsj.power.common.def.dto.locationDevice.LocationDevice2DDTO;
import com.bsj.power.common.def.dto.locationDevice.LocationDeviceDTO;
import com.bsj.power.common.def.dto.locationDevice.LocationDeviceSearchDTO;
import com.bsj.power.common.def.dto.personnel.PersonnelSearchDTO;
import com.bsj.power.common.def.entity.cardReport.CardReport;
import com.bsj.power.common.def.entity.job.Job;
import com.bsj.power.common.def.entity.job.JobPersonnel;
import com.bsj.power.common.def.entity.job.QualityPlan;
import com.bsj.power.common.def.entity.job.WorkPersonnel;
import com.bsj.power.common.def.entity.locationDevice.LocationDevice;
import com.bsj.power.common.def.entity.personnel.Personnel;
import com.bsj.power.common.def.entity.tree.Tree;
import com.bsj.power.common.def.vo.KeyValueVO;
import com.bsj.power.common.def.vo.PersonAndJobVO;
import com.bsj.power.common.def.vo.VagueVO;
import com.bsj.power.common.def.vo.pls.*;
import com.bsj.power.common.def.vo.pls.excel.AnchorDeviceExcelVO;
import com.bsj.power.common.def.vo.pls.excel.LocationDeviceExcelVO;
import com.bsj.power.common.def.vo.pls.excel.LocationDeviceTemplate;
import com.bsj.power.common.def.vo.pls.httpVo.HistoryOriginalVO;
import com.bsj.power.common.def.vo.pls.httpVo.HttpTagInfoVO;
import com.bsj.power.common.def.vo.pls.httpVo.HttpTagPosVO;
import com.bsj.power.common.def.vo.tree.TreeStructureVO;
import com.bsj.power.common.def.vo.web.job.JobCacheVO;
import com.bsj.power.common.http.PersonHttp;
import com.bsj.power.common.mapper.*;
import com.bsj.power.common.util.DataUtil;
import com.bsj.power.common.util.DateUtils;
import com.bsj.power.common.util.ParamCheckUtil;
import com.bsj.power.common.util.excel.ModelExcelListener;
import com.bsj.power.pls.file.uwbData.WRFileBaseUntil;
import com.bsj.power.pls.service.LocationDeviceService;
import com.bsj.power.pls.service.TreeService;
import com.bsj.tools.DateUntil;
import com.hikvision.artemis.sdk.ArtemisHttpUtil;
import com.hikvision.artemis.sdk.config.ArtemisConfig;
import com.hikvision.artemis.sdk.constant.ContentType;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import redis.clients.bsj.JedisClusterBSJ;

import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.text.ParseException;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.bsj.power.common.util.DateUtils.getAgeByDate;

/**
 * @author LiJiaXin
 * @version 1.0.0
 * @description LocationDeviceServiceImpl
 * @time 2024/4/19 11:59
 */
@Slf4j
@Service
public class LocationDeviceServiceImpl implements LocationDeviceService {

//    @Value("${hiKv.host}")
//    private String host;
//
//    @Value("${hiKv.appKey}")
//    private String appKey;
//
//    @Value("${hiKv.appSecret}")
//    private String appSecret;
//
//    /**
//     * url格式：https://{hostname}:{port}/artemis/{uri}。
//     */
//    private static final String ARTEMIS_PATH = "/artemis";

    /**
     * wearTypeMap:佩戴方式map
     * stateTypeMap：状态map
     */
    static Map<Integer, String> wearTypeMap, stateTypeMap;

    static {
        wearTypeMap = Map.of(NumericalConstants.ONE, "手表", NumericalConstants.TWO, "WIFI电话",
                NumericalConstants.THREE, "标签");
        stateTypeMap = Map.of(NumericalConstants.ONE, "在线", NumericalConstants.TWO, "离线",
                NumericalConstants.THREE, "报警");
    }

    @Value("${myUrl.ipHost}")
    private String ipHost;

    /**
     * true代表核电环境，false代表公司测试环境
     */
    @Value("${systemFlag}")
    private Boolean systemFlag;

    @Resource
    private LocationDeviceMapper locationDeviceMapper;

    @Resource
    private CardReportMapper cardReportMapper;

    @Resource
    private JobPersonnelMapper jobPersonnelMapper;

    @Resource
    private PersonnelMapper personnelMapper;

    @Resource
    private JobMapper jobMapper;

    @Resource
    private QualityPlanMapper qualityPlanMapper;

    @Resource
    private WorkPersonnelMapper workPersonnelMapper;

    @Autowired
    private PersonnelCached personnelCached;

    @Autowired
    private WorkPersonnelCached workPersonnelCached;

    @Autowired
    private LocationDeviceCached locationDeviceCached;

    @Autowired
    private BindCardCached bindCardCached;

    @Autowired
    private PathAlarmCached pathAlarmCached;

    @Autowired
    private JedisClusterBSJ jedisClusterBSJ;

    @Autowired
    private WRFileBaseUntil wrFileBaseUntil;

    @Resource
    private TreeMapper treeMapper;

    @Autowired
    private TreeService treeService;

    @Autowired
    private RedisCached redisCached;

    @Autowired
    private PersonHttp personHttp;

    /**
     * 添加定位设备
     *
     * @param locationDeviceDTO
     * @return com.bsj.power.common.config.global.JsonResult
     * @author ljx
     * @time 2024/4/19 11:57
     */
    @Override
    @Transactional
    public JsonResult addLocationDevice(LocationDeviceDTO locationDeviceDTO) {
        if (locationDeviceMapper.exists(Wrappers.<LocationDevice>lambdaQuery().eq(LocationDevice::getDeviceName, locationDeviceDTO.getDeviceName()))) {
            return JsonResult.fail(JsonResultEnum.DEVICE_NAME_EXIST);
        }
        Integer deviceType = locationDeviceDTO.getDeviceType();
        LocationDevice locationDevice = new LocationDevice();
        BeanUtils.copyProperties(locationDeviceDTO, locationDevice);
        if (systemFlag) {
            //数据同步
            String url = deviceType.equals(NumericalConstants.ONE) ? ApiConstants.GET_ALL_ANCHOR : ApiConstants.GET_ALL_TAG;
            List<HttpTagInfoVO> httpTagInfoVOS = getDeviceInfo(locationDevice.getDeviceName(), url);
            if (CollectionUtils.isEmpty(httpTagInfoVOS)) {
                return JsonResult.fail(JsonResultEnum.DEVICE_INFO_IS_NULL);
            }
            HttpTagInfoVO httpTagInfoVO = httpTagInfoVOS.get(NumericalConstants.ZERO);
            locationDevice.setOtherName(httpTagInfoVO.getName());
            locationDevice.setFirmware(httpTagInfoVO.getVersion());
            locationDevice.setDeviceModel(httpTagInfoVO.getProductKey());
        }
        if (locationDeviceMapper.insert(locationDevice) > NumericalConstants.ZERO) {
            locationDeviceCached.hsetLocationDeviceInfo(locationDevice);
            return JsonResult.success();
        } else {
            return JsonResult.fail();
        }
    }

    /**
     * 删除定位设备
     *
     * @param deleteDTO
     * @return com.bsj.power.common.config.global.JsonResult
     * @author ljx
     * @time 2024/4/19 11:58
     */
    @Override
    @Transactional
    public JsonResult deleteLocationDevice(DeleteDTO deleteDTO) {
        Long[] ids = deleteDTO.getIds();
        if (ids == null || ids.length == NumericalConstants.ZERO) {
            return JsonResult.fail(JsonResultEnum.PARAM_ERROR);
        }
        List<Long> idList = Arrays.asList(ids);
        QueryWrapper<LocationDevice> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("device_id", idList);
        queryWrapper.select("device_name");
        List<LocationDevice> locationDevices = locationDeviceMapper.selectList(queryWrapper);
        ParamCheckUtil.isEmpty(locationDevices, JsonResultEnum.LOCATION_DEVICE_NOT_EXIST);
        //设备处于绑卡状态无法删除
        locationDevices.forEach(locationDevice -> {
            BindCardDTO bindCardDTO = bindCardCached.hgetBindCardInfo(RedisConstant.BIND_CARD_REDIS_DEVICE_NAME_KEY + locationDevice.getDeviceName());
            ParamCheckUtil.isNotNull(bindCardDTO, JsonResultEnum.LOCATION_DEVICE_BIND_CARD);
        });
        if (locationDeviceMapper.batchDelete(idList) > NumericalConstants.ZERO) {
            locationDevices.forEach(locationDevice -> {
                locationDeviceCached.hdelLocationDeviceInfo(locationDevice.getDeviceName());
            });
            return JsonResult.success();
        } else {
            return JsonResult.fail();
        }
    }

    /**
     * 修改定位设备
     *
     * @param locationDeviceDTO
     * @return com.bsj.power.common.config.global.JsonResult
     * @author ljx
     * @time 2024/4/19 11:58
     */
    @Override
    @Transactional
    public JsonResult updateLocationDevice(LocationDeviceDTO locationDeviceDTO) {
        Long deviceId = locationDeviceDTO.getDeviceId();
        ParamCheckUtil.isNull(deviceId);
        LocationDevice oldLocationDevice = locationDeviceMapper.selectById(deviceId);
        ParamCheckUtil.isNull(oldLocationDevice, JsonResultEnum.LOCATION_DEVICE_NOT_EXIST);
        if (!oldLocationDevice.getDeviceName().equals(locationDeviceDTO.getDeviceName())) {
            return JsonResult.fail(JsonResultEnum.DEVICE_NAME_CANNOT_UPDATE);
        }
        LocationDevice locationDevice = new LocationDevice();
        BeanUtils.copyProperties(locationDeviceDTO, locationDevice);
        LambdaUpdateWrapper<LocationDevice> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.eq(LocationDevice::getDeviceId, deviceId);
        if (StringUtils.isBlank(locationDevice.getNikeName())) {
            updateWrapper.set(LocationDevice::getNikeName, null);
        }
        if (StringUtils.isBlank(locationDevice.getOtherName())) {
            updateWrapper.set(LocationDevice::getOtherName, null);
        }
        if (StringUtils.isBlank(locationDevice.getManufacturer())) {
            updateWrapper.set(LocationDevice::getManufacturer, null);
        }
        Integer treeId = locationDevice.getTreeId();
        if (treeId == null) {
            updateWrapper.set(LocationDevice::getTreeId, null);
        } else {
            Tree tree = treeMapper.selectById(treeId);
            ParamCheckUtil.isNull(tree, JsonResultEnum.TREE_BRANCH_ISNULL);
        }
        if (locationDeviceMapper.update(locationDevice, updateWrapper) > NumericalConstants.ZERO) {
            locationDeviceCached.hsetLocationDeviceInfo(locationDevice);
            return JsonResult.success();
        } else {
            return JsonResult.fail();
        }
    }

    /**
     * 获取单个定位设备
     *
     * @param deviceId
     * @return com.bsj.power.common.def.vo.pls.LocationDeviceVO
     * @author ljx
     * @time 2024/4/19 11:58
     */
    @Override
    public LocationDeviceVO getLocationDeviceById(Long deviceId) {
        ParamCheckUtil.isNull(deviceId);
        LocationDevice locationDevice = locationDeviceMapper.selectById(deviceId);
        ParamCheckUtil.isNull(locationDevice, JsonResultEnum.LOCATION_DEVICE_NOT_EXIST);
        LocationDeviceVO locationDeviceVO = new LocationDeviceVO();
        BeanUtils.copyProperties(locationDevice, locationDeviceVO);
        return locationDeviceVO;
    }

    /**
     * 定位设备分页
     *
     * @param locationDeviceSearchDTO
     * @return com.bsj.power.common.config.global.JsonResult<java.util.List < com.bsj.power.common.def.vo.pls.LocationDeviceVO>>
     * @author ljx
     * @time 2024/4/19 11:58
     */
    @Override
    public JsonResult<List<LocationDeviceVO>> pageLocationDevice(LocationDeviceSearchDTO locationDeviceSearchDTO) {
        long total = NumericalConstants.ZERO;
        Map<String, HttpTagInfoVO> tagInfoMap = new HashMap<>();
        List<String> deviceNames = null;
        //七天前的时间
        long time = new Date().getTime() - 1000 * 60 * 60 * 24 * 7;
        System.out.println("七天前的时间" + DateUtils.dateToStr(new Date(time)));
        long dateTime = new Date(time).getTime();
        //TODO 此处参数处理需区分环境
        if (systemFlag) {
            deviceNames = paramHandleOne(locationDeviceSearchDTO, tagInfoMap, dateTime);
        } else {
            deviceNames = paramHandleTwo(locationDeviceSearchDTO, tagInfoMap, dateTime);
        }
        if (CollectionUtils.isEmpty(deviceNames)) {
            return JsonResult.success(new ArrayList<>(), total);
        }
        locationDeviceSearchDTO.setDeviceNames(deviceNames);
        Integer treeId = locationDeviceSearchDTO.getTreeId();
        if (treeId != null) {
            List<Integer> treeIds = treeService.getTreeIds(treeId, NumericalConstants.TWO);
            locationDeviceSearchDTO.setTreeIds(treeIds);
        }
        total = locationDeviceMapper.countLocationDevice(locationDeviceSearchDTO);
        if (total == NumericalConstants.ZERO) {
            return JsonResult.success(new ArrayList<>(), total);
        }
        Integer state = locationDeviceSearchDTO.getState();
        Boolean isReturn = locationDeviceSearchDTO.getIsReturn();
        locationDeviceSearchDTO.initPageNumber();
        locationDeviceSearchDTO.setSearchType(NumericalConstants.ONE);
        List<LocationDeviceVO> locationDeviceVOS = locationDeviceMapper.pageLocationDevice(locationDeviceSearchDTO);
        for (LocationDeviceVO locationDeviceVO : locationDeviceVOS) {
            String deviceName = locationDeviceVO.getDeviceName();
            BindCardDTO bindCardDTO = bindCardCached.hgetBindCardInfo(RedisConstant.BIND_CARD_REDIS_DEVICE_NAME_KEY + deviceName);
            if (!locationDeviceVO.getDeviceType().equals(NumericalConstants.ONE)) {
                if (bindCardDTO != null) {
                    locationDeviceVO.setBindCardDTO(bindCardDTO);
                    locationDeviceVO.setBindCardState(NumericalConstants.ONE);
                } else {
                    locationDeviceVO.setBindCardState(NumericalConstants.TWO);
                }
                String str = jedisClusterBSJ.get(UWBPosConstant.REDIS_TAG_POS_KEY + deviceName);
                if (StringUtils.isNotBlank(str)) {
                    locationDeviceVO.setHttpTagPosVO(JSONObject.parseObject(str, HttpTagPosVO.class));
                }
            }
            if (state != null) {
                locationDeviceVO.setState(state);
            } else {
                //默认离线
                int tempState = NumericalConstants.TWO;
                if (!CollectionUtils.isEmpty(tagInfoMap)) {
                    HttpTagInfoVO httpTagInfoVO = tagInfoMap.get(deviceName);
                    if (httpTagInfoVO != null && httpTagInfoVO.getOnline()) {
                        tempState = NumericalConstants.ONE;
                    }
                }
                locationDeviceVO.setState(tempState);
            }
            if (isReturn != null && isReturn) {
                locationDeviceVO.setIsReturn(NumericalConstants.ONE);
            } else {
                if (bindCardDTO != null) {
                    Date bindTime = bindCardDTO.getBindTime();
                    //核电环境
                    if (systemFlag) {
                        Integer bindWay = bindCardDTO.getBindWay();
                        if (bindWay != null && bindWay.equals(NumericalConstants.TWO) && bindTime != null && bindTime.getTime() < dateTime) {
                            locationDeviceVO.setIsReturn(NumericalConstants.ONE);
                        }
                    } else {
                        //公司测试环境
                        if (bindTime != null && bindTime.getTime() < dateTime) {
                            locationDeviceVO.setIsReturn(NumericalConstants.ONE);
                        }
                    }
                }
            }
            LocationDevice locationDevice = locationDeviceCached.hgetLocationDeviceInfo(deviceName);
            if (locationDevice != null && StringUtils.isNotBlank(locationDevice.getPersonName())) {
                locationDeviceVO.setPersonName(locationDevice.getPersonName());
            }
        }
        return JsonResult.success(locationDeviceVOS, total);
    }

    /**
     * 设置人员与工单信息
     *
     * @param empNo
     * @param locationDeviceVO
     * @return void
     * @author ljx
     * @time 2024/9/15 11:06
     */
    private void setJobInfo(String empNo, LocationDeviceVO locationDeviceVO) {
        Personnel personnel = personnelMapper.selectOne(Wrappers.<Personnel>lambdaQuery().eq(Personnel::getEmpNo, empNo));
        WorkPersonnel workPersonnel = workPersonnelMapper.selectOne(Wrappers.<WorkPersonnel>lambdaQuery().eq(WorkPersonnel::getTemporaryEmpNo, empNo));
        if (personnel == null && workPersonnel == null) {
            return;
        }
        List<Job> jobs = null;
        Date date = new Date();
        if (personnel != null) {
            jobs = jobMapper.selectList(Wrappers.<Job>lambdaQuery().le(Job::getStartTime, date)
                    .ge(Job::getEndTime, date).eq(Job::getDirectorId, personnel.getDirectorId()));
        } else {
            List<JobPersonnel> jobPersonnelList = jobPersonnelMapper.selectList(Wrappers.<JobPersonnel>lambdaQuery()
                    .eq(JobPersonnel::getPersonnelId, workPersonnel.getWorkPersonnelId()));
            if (!CollectionUtils.isEmpty(jobPersonnelList)) {
                List<Long> jobIds = jobPersonnelList.stream().map(JobPersonnel::getJobId).collect(Collectors.toList());
                jobs = jobMapper.selectList(Wrappers.<Job>lambdaQuery().le(Job::getStartTime, date)
                        .ge(Job::getEndTime, date).in(Job::getJobId, jobIds));
            }
        }
        if (!CollectionUtils.isEmpty(jobs)) {
            locationDeviceVO.setJobNames(jobs.stream().sorted(Comparator.comparing(Job::getStartTime).reversed()).map(Job::getDescription).collect(Collectors.toList()));
        }
    }

    /**
     * 参数处理1
     * TODO 核电环境使用
     *
     * @param locationDeviceSearchDTO
     * @param tagInfoMap
     * @param dateTime
     * @return java.util.List<java.lang.String>
     * @author ljx
     * @time 2024/9/5 19:51
     */
    private List<String> paramHandleOne(LocationDeviceSearchDTO locationDeviceSearchDTO, Map<String, HttpTagInfoVO> tagInfoMap, Long dateTime) {
        List<String> deviceNames = new LinkedList<>();
        Boolean isBind = locationDeviceSearchDTO.getIsBind();
        String devName = locationDeviceSearchDTO.getDeviceName();
        Integer deviceType = locationDeviceSearchDTO.getDeviceType();
        String empNo = locationDeviceSearchDTO.getEmpNo();
        Boolean isReturn = locationDeviceSearchDTO.getIsReturn();
        List<HttpTagInfoVO> httpTagInfoVOS = new LinkedList<>();
        //查询关联人员
        if (StringUtils.isNotBlank(empNo)) {
            BindCardDTO bindCardDTO = bindCardCached.hgetBindCardInfo(RedisConstant.BIND_CARD_REDIS_EMP_NO_KEY + empNo);
            if (bindCardDTO != null) {
                devName = bindCardDTO.getDeviceName();
            } else {
                return deviceNames;
            }
        }
        if (deviceType != null) {
            if (deviceType < NumericalConstants.ONE || deviceType > NumericalConstants.THREE) {
                throw new ApiException(JsonResultEnum.PARAM_ERROR);
            }
            if (deviceType.equals(NumericalConstants.ONE)) {
                //基站设备
                httpTagInfoVOS = getDeviceInfo(devName, ApiConstants.GET_ALL_ANCHOR);
            } else {
                //标签定位设备
                httpTagInfoVOS = getDeviceInfo(devName, ApiConstants.GET_ALL_TAG);
            }
        } else {
            //如果为空基站设备与标签设备都需要查询
            List<HttpTagInfoVO> anchorData = getDeviceInfo(devName, ApiConstants.GET_ALL_ANCHOR);
            if (!CollectionUtils.isEmpty(anchorData)) {
                httpTagInfoVOS.addAll(anchorData);
            }
            List<HttpTagInfoVO> tagData = getDeviceInfo(devName, ApiConstants.GET_ALL_TAG);
            if (!CollectionUtils.isEmpty(tagData)) {
                httpTagInfoVOS.addAll(tagData);
            }
        }
        //状态查询
        Integer state = locationDeviceSearchDTO.getState();
        if (state != null) {
            if (!CollectionUtils.isEmpty(httpTagInfoVOS)) {
                if (state.equals(NumericalConstants.ONE)) {
                    //在线
                    httpTagInfoVOS = httpTagInfoVOS.stream().filter(httpTagInfoVO -> httpTagInfoVO.getOnline()).collect(Collectors.toList());
                } else if (state.equals(NumericalConstants.TWO)) {
                    //离线
                    httpTagInfoVOS = httpTagInfoVOS.stream().filter(httpTagInfoVO -> !httpTagInfoVO.getOnline()).collect(Collectors.toList());
                } /*else if (state.equals(NumericalConstants.THREE)) {
                    //报警
                    httpTagInfoVOS = httpTagInfoVOS.stream().filter(httpTagInfoVO -> !CollectionUtils.isEmpty(pathAlarmCached.hgetAllPathAlarmInfo(httpTagInfoVO.getSn()))).collect(Collectors.toList());
                }*/ else {
                    throw new ApiException(JsonResultEnum.PARAM_ERROR);
                }
            }
        }
        //只返回绑卡的设备，这种情况下绑卡信息与位置数据都要返回
        if (isBind != null && isBind) {
            if (!CollectionUtils.isEmpty(httpTagInfoVOS)) {
                httpTagInfoVOS = httpTagInfoVOS.stream().filter(httpTagInfoVO -> bindCardCached.hgetBindCardInfo(RedisConstant.BIND_CARD_REDIS_DEVICE_NAME_KEY + httpTagInfoVO.getSn()) != null).collect(Collectors.toList());
            }
        }
        //检索绑卡方式为人脸识别绑卡后7天未归还的设备
        if (isReturn != null && isReturn) {
            if (!CollectionUtils.isEmpty(httpTagInfoVOS)) {
                httpTagInfoVOS = httpTagInfoVOS.stream().filter(httpTagInfoVO -> filterReturnDevice(httpTagInfoVO, dateTime)).collect(Collectors.toList());
            }
        }
        if (!CollectionUtils.isEmpty(httpTagInfoVOS)) {
            for (HttpTagInfoVO httpTagInfoVO : httpTagInfoVOS) {
                String sn = httpTagInfoVO.getSn();
                deviceNames.add(sn);
                tagInfoMap.put(sn, httpTagInfoVO);
            }
        }
        return deviceNames;
    }

    /**
     * 筛选出绑卡方式为人脸识别绑卡后7天未归还的设备
     *
     * @param httpTagInfoVO
     * @param dateTime
     * @return boolean
     * @author ljx
     * @time 2024/12/19 20:11
     */
    private boolean filterReturnDevice(HttpTagInfoVO httpTagInfoVO, long dateTime) {
        BindCardDTO bindCardDTO = bindCardCached.hgetBindCardInfo(RedisConstant.BIND_CARD_REDIS_DEVICE_NAME_KEY + httpTagInfoVO.getSn());
        if (bindCardDTO != null) {
            Integer bindWay = bindCardDTO.getBindWay();
            Date bindTime = bindCardDTO.getBindTime();
            if (bindWay != null && bindWay.equals(NumericalConstants.TWO) && bindTime != null && bindTime.getTime() < dateTime) {
                return true;
            }
        }
        return false;
    }

    /**
     * 参数处理2
     * TODO 公司测试环境使用
     *
     * @param locationDeviceSearchDTO
     * @return void
     * @author ljx
     * @time 2024/9/4 15:06
     */
    private List<String> paramHandleTwo(LocationDeviceSearchDTO locationDeviceSearchDTO, Map<String, HttpTagInfoVO> tagInfoMap, Long dateTime) {
        List<String> deviceNames = new LinkedList<>();
        Integer state = locationDeviceSearchDTO.getState();
        Boolean isBind = locationDeviceSearchDTO.getIsBind();
        String devName = locationDeviceSearchDTO.getDeviceName();
        Integer deviceType = locationDeviceSearchDTO.getDeviceType();
        String empNo = locationDeviceSearchDTO.getEmpNo();
        Boolean isReturn = locationDeviceSearchDTO.getIsReturn();
        List<LocationDevice> locationDevices = new LinkedList<>();
        //查询关联人员
        if (StringUtils.isNotBlank(empNo)) {
            BindCardDTO bindCardDTO = bindCardCached.hgetBindCardInfo(RedisConstant.BIND_CARD_REDIS_EMP_NO_KEY + empNo);
            if (bindCardDTO != null) {
                devName = bindCardDTO.getDeviceName();
            } else {
                return deviceNames;
            }
        }
        if (StringUtils.isNotBlank(devName)) {
            LocationDevice locationDevice = locationDeviceCached.hgetLocationDeviceInfo(devName);
            if (locationDevice != null) {
                locationDevices.add(locationDevice);
            }
        } else {
            locationDevices = locationDeviceCached.hgetAllLocationDeviceInfo();
        }
        if (!CollectionUtils.isEmpty(locationDevices)) {
            if (deviceType != null) {
                if (deviceType < NumericalConstants.ONE || deviceType > NumericalConstants.THREE) {
                    throw new ApiException(JsonResultEnum.PARAM_ERROR);
                }
                if (deviceType.equals(NumericalConstants.ONE)) {
                    //基站设备
                    locationDevices = locationDevices.stream().filter(locationDevice -> locationDevice.getDeviceType().equals(NumericalConstants.ONE)).collect(Collectors.toList());
                } /*else if (deviceType.equals(NumericalConstants.TWO)) {
                    //UWB设备
                    locationDevices = locationDevices.stream().filter(locationDevice -> locationDevice.getDeviceType().equals(NumericalConstants.TWO)).collect(Collectors.toList());
                }*/ else {
                    //UWB+北斗设备（改为基站以外的设备）
                    locationDevices = locationDevices.stream().filter(locationDevice -> !locationDevice.getDeviceType().equals(NumericalConstants.ONE)).collect(Collectors.toList());
                }
            }
            //状态查询
            if (state != null) {
                if (state.equals(NumericalConstants.ONE)) {
                    //无在线设备
                    locationDevices = null;
                } /*else if (state.equals(NumericalConstants.THREE)) {
                    //报警
                    if (!CollectionUtils.isEmpty(locationDevices)) {
                        locationDevices = locationDevices.stream().filter(locationDevice -> !CollectionUtils.isEmpty(pathAlarmCached.hgetAllPathAlarmInfo(locationDevice.getDeviceName()))).collect(Collectors.toList());
                    }
                }*/
                //TODO 公司测试环境定位设备默认全部离线
            }
            //只返回绑卡的设备，这种情况下绑卡信息与位置数据都要返回
            if (isBind != null && isBind) {
                if (!CollectionUtils.isEmpty(locationDevices)) {
                    locationDevices = locationDevices.stream().filter(locationDevice -> bindCardCached.hgetBindCardInfo(RedisConstant.BIND_CARD_REDIS_DEVICE_NAME_KEY + locationDevice.getDeviceName()) != null).collect(Collectors.toList());
                }
            }

            //检索绑卡方式为人脸识别绑卡后7天未归还的设备（公司测试环境无人脸识别绑卡，因此不做区分）
            if (isReturn != null && isReturn) {
                if (!CollectionUtils.isEmpty(locationDevices)) {
                    locationDevices = locationDevices.stream().filter(locationDevice -> testFilterReturnDevice(locationDevice, dateTime)).collect(Collectors.toList());
                }
            }
        }
        if (!CollectionUtils.isEmpty(locationDevices)) {
            deviceNames = locationDevices.stream().map(LocationDevice::getDeviceName).collect(Collectors.toList());
        }
        return deviceNames;
    }

    /**
     * 公司测试环境筛选出绑卡后7天未归还的设备
     *
     * @param locationDevice
     * @param dateTime
     * @return boolean
     * @author ljx
     * @time 2024/12/20 9:45
     */
    private boolean testFilterReturnDevice(LocationDevice locationDevice, long dateTime) {
        BindCardDTO bindCardDTO = bindCardCached.hgetBindCardInfo(RedisConstant.BIND_CARD_REDIS_DEVICE_NAME_KEY + locationDevice.getDeviceName());
        if (bindCardDTO != null) {
            Date bindTime = bindCardDTO.getBindTime();
            if (bindTime != null && bindTime.getTime() < dateTime) {
                return true;
            }
        }
        return false;
    }

    /**
     * 是否绑定
     *
     * @param bindCardDTO
     * @param isRepetitionName 是否重名 1是  2否
     * @return com.bsj.power.common.config.global.JsonResult
     * @author ljx
     * @time 2024/5/8 17:10
     */
    @Override
    @Transactional
    public JsonResult isBind(BindCardDTO bindCardDTO, Integer isRepetitionName) {
        //人员类型分类 0:负责人 1:作业人员
        Integer classify = bindCardDTO.getClassify();
        Integer type = bindCardDTO.getType();
        String empNo = bindCardDTO.getEmpNo();
        String workName = bindCardDTO.getPersonnelName();
        String deviceName = bindCardDTO.getDeviceName();
        Integer bindWay = bindCardDTO.getBindWay();
        //负责人员信息
        Personnel personnel = personnelMapper.selectOne(Wrappers.<Personnel>lambdaQuery().eq(Personnel::getEmpNo, empNo));
        //作业人员信息
        WorkPersonnel workPersonnel = workPersonnelMapper.selectOne(Wrappers.<WorkPersonnel>lambdaQuery().eq(WorkPersonnel::getTemporaryEmpNo, empNo));
        if (workPersonnel == null) {
            workPersonnel = workPersonnelMapper.selectOne(Wrappers.<WorkPersonnel>lambdaQuery()
                    .eq(WorkPersonnel::getTemporaryEmpNo, empNo).eq(WorkPersonnel::getName, workName));
            if (workPersonnel != null) {
                //临时缓存作业人员信息
                workPersonnelCached.setWorkPersonnelInfo(workPersonnel);
            }
        }
        if (personnel == null && workPersonnel == null) {
            return JsonResult.fail(JsonResultEnum.PERSONNEL_NOT_EXIST);
        }
        String idCardNo = bindCardDTO.getIdCardNo();
        if (StringUtils.isNotBlank(idCardNo)) {
            if (personnel != null) {
                String personIdCardNo = personnel.getIdCardNo();
                if (StringUtils.isNotBlank(personIdCardNo) && !personIdCardNo.equals(idCardNo)) {
                    return JsonResult.fail(JsonResultEnum.PERSONNEL_INFO_ERROR);
                }
            }
            if (workPersonnel != null) {
                String workPersonIdCardNo = workPersonnel.getIdCardNo();
                if (StringUtils.isNotBlank(workPersonIdCardNo) && !workPersonIdCardNo.equals(idCardNo)) {
                    return JsonResult.fail(JsonResultEnum.PERSONNEL_INFO_ERROR);
                }
            }
        }
        LocationDevice locationDevice = locationDeviceCached.hgetLocationDeviceInfo(deviceName);
        if (locationDevice == null) {
            return JsonResult.fail(JsonResultEnum.LOCATION_DEVICE_NOT_EXIST);
        }
        if (locationDevice.getDeviceType().equals(NumericalConstants.ONE)) {
            return JsonResult.fail(JsonResultEnum.ANCHOR_DEVICE_UNABLE_TO_BIND);
        }
        Date date = new Date();
        BindCardDTO oldBindCardDTO = bindCardCached.hgetBindCardInfo(RedisConstant.BIND_CARD_REDIS_EMP_NO_KEY + empNo);
        if (type.equals(NumericalConstants.ONE)) {
            // 正在绑定状态的人员或设备无法再次绑定
            if (oldBindCardDTO != null) {
                return JsonResult.fail(JsonResultEnum.PERSONNEL_ALREADY_BIND_CARD);
            }
            oldBindCardDTO = bindCardCached.hgetBindCardInfo(RedisConstant.BIND_CARD_REDIS_DEVICE_NAME_KEY + deviceName);
            if (oldBindCardDTO != null) {
                return JsonResult.fail(JsonResultEnum.LOCATION_DEVICE_ALREADY_BIND_PERSONNEL);
            }
            Integer isLockIn = locationDevice.getIsLockIn();
            if (isLockIn != null && isLockIn.equals(NumericalConstants.ONE)) {
                return JsonResult.fail(JsonResultEnum.LOCATION_DEVICE_IS_LOCK_IN);
            }
            bindCardDTO.setBindTime(date);
        } else {
            // 无绑定状态的人员或设备无需退卡
            if (oldBindCardDTO == null) {
                return JsonResult.fail(JsonResultEnum.PERSONNEL_NOT_BIND_CARD);
            }
            oldBindCardDTO = bindCardCached.hgetBindCardInfo(RedisConstant.BIND_CARD_REDIS_DEVICE_NAME_KEY + deviceName);
            if (oldBindCardDTO == null) {
                return JsonResult.fail(JsonResultEnum.LOCATION_DEVICE_NOT_BIND_PERSONNEL);
            }
        }
        if (StringUtils.isBlank(bindCardDTO.getRemark())) {
            bindCardDTO.setRemark(type.equals(NumericalConstants.ONE) ? "手动绑卡" : "手动退卡");
        }
        String startTime = DateUtils.getStartOfDay2(date);
        String endTime = DateUtils.getEndOfDay2(date);
        String extEventPersonNo = null;
        //添加流水记录
        CardReport cardReport;
        if (personnel != null) {
            bindCardDTO.setPhone(personnel.getPhone());
            cardReport = new CardReport(bindCardDTO, personnel);
            extEventPersonNo = personnel.getExtEventPersonNo();
            //负责人
            cardReport.setClassify(NumericalConstants.ZERO);
            String directorId = personnel.getDirectorId();
            QueryWrapper<Job> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("director_id", directorId);
            queryWrapper.between("create_time", startTime, endTime);
            queryWrapper.ne("status", NumericalConstants.TWO);
            //未完成的工单
            List<Job> jobs = jobMapper.selectList(queryWrapper);
            if (!CollectionUtils.isEmpty(jobs)) {
                cardReport.setJobId(jobs.stream().map(Job::getJobId).map(String::valueOf).collect(Collectors.joining(",")));
                List<String> jobNumList = jobs.stream().map(Job::getJobNum).collect(Collectors.toList());
                List<JobCacheVO> jobCacheVOS = jobs.stream().map(job -> {
                    JobCacheVO jobCacheVO = new JobCacheVO(job);
                    jobCacheVO.setEmpNo(empNo);
                    if (!CollectionUtils.isEmpty(jobNumList)) {
                        jobCacheVO.setQualityPlans(qualityPlanMapper.selectList(Wrappers.<QualityPlan>lambdaQuery().in(QualityPlan::getJobNum, jobNumList)));
                    }
                    return jobCacheVO;
                }).collect(Collectors.toList());
                bindCardDTO.setJobCacheVOS(jobCacheVOS);
            }
        } else if (workPersonnel != null) {
            cardReport = new CardReport(bindCardDTO, workPersonnel);
            extEventPersonNo = workPersonnel.getExtEventPersonNo();
            //作业人员
            cardReport.setClassify(NumericalConstants.ONE);
            bindCardDTO.setPhone(workPersonnel.getPhone());
            // 查询作业人员与作业关系表确定当前作业是哪些
            PersonnelSearchDTO personnelSearchDTO = new PersonnelSearchDTO();
            personnelSearchDTO.setStartTime(startTime);
            personnelSearchDTO.setEndTime(endTime);
            personnelSearchDTO.setPersonnelId(workPersonnel.getWorkPersonnelId());
            List<Long> jobIds = jobPersonnelMapper.getPresentJob(personnelSearchDTO);
            if (!CollectionUtils.isEmpty(jobIds)) {
                cardReport.setJobId(jobIds.stream().map(String::valueOf).collect(Collectors.joining(",")));
                List<Job> jobs = jobMapper.selectList(Wrappers.<Job>lambdaQuery().in(Job::getJobId, jobIds).ne(Job::getStatus, NumericalConstants.TWO));
                if (!CollectionUtils.isEmpty(jobs)) {
                    List<String> directorIds = jobs.stream().map(Job::getDirectorId).collect(Collectors.toList());
                    if (!CollectionUtils.isEmpty(directorIds)) {
                        //负责人员集
                        List<Personnel> personnelList = personnelMapper.selectList(Wrappers.<Personnel>lambdaQuery().in(Personnel::getDirectorId, directorIds));
                        if (!CollectionUtils.isEmpty(personnelList)) {
                            List<String> jobNumList = jobs.stream().map(Job::getJobNum).collect(Collectors.toList());
                            Map<String, Personnel> personnelMap = personnelList.stream().collect(Collectors.toMap(Personnel::getDirectorId, Function.identity()));
                            List<JobCacheVO> jobCacheVOS = jobs.stream().map(job -> {
                                JobCacheVO jobCacheVO = new JobCacheVO(job);
                                Personnel tempPersonnel = personnelMap.get(job.getDirectorId());
                                if (tempPersonnel != null) {
                                    jobCacheVO.setEmpNo(tempPersonnel.getEmpNo());
                                }
                                if (!CollectionUtils.isEmpty(jobNumList)) {
                                    jobCacheVO.setQualityPlans(qualityPlanMapper.selectList(Wrappers.<QualityPlan>lambdaQuery().in(QualityPlan::getJobNum, jobNumList)));
                                }
                                return jobCacheVO;
                            }).collect(Collectors.toList());
                            bindCardDTO.setJobCacheVOS(jobCacheVOS);
                        }
                    }
                }
            }
        } else {
            return JsonResult.fail(JsonResultEnum.PERSONNEL_NOT_EXIST);
        }
//        //退卡操作时，防止绑卡后人员姓名被修改，依旧使用绑卡时的姓名
//        if (type.equals(NumericalConstants.TWO)) {
//            cardReport.setPersonnelName(oldBindCardDTO.getPersonnelName());
//        }
//        if (type.equals(NumericalConstants.TWO)) {
//            cardReport.setUpdateTime(date);
//        }
//        //作用于自动绑卡工牌弹出信息上报处理方法cpDataHandle补充
//        if (type.equals(NumericalConstants.ONE) && bindWay.equals(NumericalConstants.TWO)) {
//            extEventPersonNo = bindCardDTO.getExtEventPersonNo();
//        }
        //优先使用绑卡对象内的
        if (StringUtils.isNotBlank(bindCardDTO.getExtEventPersonNo())) {
            extEventPersonNo = bindCardDTO.getExtEventPersonNo();
        }
        cardReport.setIsRepetitionName(isRepetitionName);
        if (cardReportMapper.insert(cardReport) > NumericalConstants.ZERO) {
            // 如果是绑卡则添加缓存反之删除
            if (type.equals(NumericalConstants.ONE)) {
                //核电环境需要执行的操作
//                if (systemFlag) {
                //如果是手动绑卡则数据库填充人员编号
//                if (bindWay.equals(NumericalConstants.ONE)) {
//                    if (StringUtils.isBlank(extEventPersonNo)) {
//                        extEventPersonNo = personHttp.getExtEventPersonNoByIdCardNo(idCardNo);
//                        //也有可能查询不到
//                        if (StringUtils.isNotBlank(extEventPersonNo)) {
//                            if (personnel != null) {
//                                personnelMapper.updateById(new Personnel(personnel.getPersonnelId(), extEventPersonNo));
//                            }
//                            if (workPersonnel != null) {
//                                workPersonnelMapper.updateById(new WorkPersonnel(workPersonnel.getWorkPersonnelId(), extEventPersonNo));
//                            }
//                        }
//                    }
//                        if (StringUtils.isNotBlank(extEventPersonNo)) {
//                            //添加安防平台人员编号缓存
//                            redisCached.set(RedisConstant.EXT_EVENT_PERSON_NO_KEY + extEventPersonNo, extEventPersonNo);
//                        }
                bindCardDTO.setExtEventPersonNo(extEventPersonNo);
                bindCardCached.hsetBindCardInfo(bindCardDTO);
                //重新添加人员编号缓存，防止多次弹卡
                redisCached.set(RedisConstant.EXT_EVENT_PERSON_NO_KEY + extEventPersonNo, extEventPersonNo);
//                }
            } else {
                bindCardCached.hdelBindCardInfo(empNo, deviceName);
                if (StringUtils.isNotBlank(extEventPersonNo)) {
                    //删除安防平台人员编号缓存
                    redisCached.del(RedisConstant.EXT_EVENT_PERSON_NO_KEY + extEventPersonNo);
                }
            }
            //删除该卡的围栏报警记录，防止脏数据
            pathAlarmCached.hdelPathAlarmInfo(deviceName);
            redisCached.del(RedisConstant.PATH_REMAIN_ALARM_KEY + deviceName);
            return JsonResult.success();
        } else {
            return JsonResult.fail();
        }

    }

    /**
     * 模糊搜索
     *
     * @param value
     * @param deviceType
     * @return java.util.List<com.bsj.power.common.def.vo.KeyValueVO>
     * @author ljx
     * @time 2024/5/15 16:10
     */
    @Override
    public List<KeyValueVO> fuzzySearch(String value, Integer deviceType) {
        List<KeyValueVO> keyValueVOS = new LinkedList<>();
        if (StringUtils.isBlank(value)) {
            return keyValueVOS;
        }
        value = DataUtil.escape(value);
        List<KeyValueVO> deviceNames = locationDeviceMapper.fuzzySearch(value, NumericalConstants.ONE, deviceType);
        List<KeyValueVO> nikeNames = locationDeviceMapper.fuzzySearch(value, NumericalConstants.TWO, deviceType);
        List<KeyValueVO> otherNames = locationDeviceMapper.fuzzySearch(value, NumericalConstants.THREE, deviceType);
        keyValueVOS.addAll(deviceNames.stream().map(keyValueVO -> {
            keyValueVO.setType(NumericalConstants.ONE);
            return keyValueVO;
        }).collect(Collectors.toList()));
        keyValueVOS.addAll(nikeNames.stream().map(keyValueVO -> {
            keyValueVO.setType(NumericalConstants.TWO);
            return keyValueVO;
        }).collect(Collectors.toList()));
        keyValueVOS.addAll(otherNames.stream().map(keyValueVO -> {
            keyValueVO.setType(NumericalConstants.THREE);
            return keyValueVO;
        }).collect(Collectors.toList()));
        return keyValueVOS;
    }


    /**
     * 轨迹页面设备或人员模糊搜索
     *
     * @param value
     * @return
     */
    @Override
    public List<VagueVO> fuzzySearch2(String value) {
        // 模糊搜索，查设备表，人员表，作业人员表三个表
        // 1设备表
        List<VagueVO> vagueVOS = new ArrayList<>();
        if (StringUtils.isEmpty(value)) {
            // 如果传入空，默认按照设备时间返回20条数据
            int pageSize = 20;
            List<LocationDevice> locationDevices = locationDeviceMapper.selectListDescTime(pageSize);
            for (LocationDevice locationDevice : locationDevices) {
                VagueVO vagueVO = new VagueVO();
                vagueVO.setType(1);
                vagueVO.setLocationDeviceId(locationDevice.getDeviceName());
                vagueVO.setLocationDeviceName(locationDevice.getNikeName());
                vagueVOS.add(vagueVO);
                return vagueVOS;
            }
        }

        value = DataUtil.escape(value);
        QueryWrapper<LocationDevice> deviceWrapper = new QueryWrapper<>();
        deviceWrapper.like("device_name", value);
        deviceWrapper.ne("device_type", 1);
        List<LocationDevice> locationDevices = locationDeviceMapper.selectList(deviceWrapper);
        if (!CollectionUtils.isEmpty(locationDevices)) {
            for (LocationDevice locationDevice : locationDevices) {
                VagueVO vagueVO = new VagueVO();
                vagueVO.setType(1);
                vagueVO.setLocationDeviceId(locationDevice.getDeviceName());
                vagueVO.setLocationDeviceName(locationDevice.getNikeName());
                vagueVOS.add(vagueVO);
            }
        }
        // 2人员表
        QueryWrapper<Personnel> personnelQueryWrapper = new QueryWrapper<>();
        personnelQueryWrapper.like("name", value);
        List<Personnel> personnels = personnelMapper.selectList(personnelQueryWrapper);
        if (!CollectionUtils.isEmpty(personnels)) {
            for (Personnel personnel : personnels) {
                VagueVO vagueVO = new VagueVO();
                vagueVO.setType(2);
                vagueVO.setPersonnelName(personnel.getName());
                vagueVO.setPersonnelEmpNo(personnel.getEmpNo());
                vagueVOS.add(vagueVO);
            }
        }
        // 3作业人员表
        QueryWrapper<WorkPersonnel> workPersonnelQueryWrapper = new QueryWrapper<>();
        workPersonnelQueryWrapper.like("name", value);
        List<WorkPersonnel> workPersonnels = workPersonnelMapper.selectList(workPersonnelQueryWrapper);
        if (!CollectionUtils.isEmpty(workPersonnels)) {
            for (WorkPersonnel workPersonnel : workPersonnels) {
                VagueVO vagueVO = new VagueVO();
                vagueVO.setType(2);
                vagueVO.setPersonnelName(workPersonnel.getName());
                vagueVO.setPersonnelEmpNo(workPersonnel.getTemporaryEmpNo());
                vagueVOS.add(vagueVO);
            }
        }

        // 如果为空，直接返回，交给controller处理
        if (CollectionUtils.isEmpty(vagueVOS)) {
            return vagueVOS;
        }

        // 按类型排序
        List<VagueVO> sorted = vagueVOS.stream().sorted(Comparator.comparing(VagueVO::getType))
                .collect(Collectors.toList());

        return sorted;
    }


    /**
     * 获取导出数据
     *
     * @param locationDeviceSearchDTO
     * @return java.util.List<com.bsj.power.common.def.vo.pls.excel.LocationDeviceExcelVO>
     * @author ljx
     * @time 2024/5/16 16:26
     */
    @Override
    public List<LocationDeviceExcelVO> getExportData(LocationDeviceSearchDTO locationDeviceSearchDTO) {
        Map<String, HttpTagInfoVO> tagInfoMap = new HashMap<>();
        List<String> deviceNames = null;
        //七天前的时间
        long time = new Date().getTime() - 1000 * 60 * 60 * 24 * 7;
        long dateTime = new Date(time).getTime();
        //TODO 此处参数处理需区分环境
        if (systemFlag) {
            deviceNames = paramHandleOne(locationDeviceSearchDTO, tagInfoMap, dateTime);
        } else {
            deviceNames = paramHandleTwo(locationDeviceSearchDTO, tagInfoMap, dateTime);
        }
        List<LocationDeviceExcelVO> locationDeviceExcelVOS = new LinkedList<>();
        if (CollectionUtils.isEmpty(deviceNames)) {
            return locationDeviceExcelVOS;
        }
        Integer state = locationDeviceSearchDTO.getState();
        Boolean isReturn = locationDeviceSearchDTO.getIsReturn();
        locationDeviceSearchDTO.setDeviceNames(deviceNames);
        locationDeviceSearchDTO.setSearchType(NumericalConstants.TWO);
        List<LocationDeviceVO> locationDeviceVOS = locationDeviceMapper.pageLocationDevice(locationDeviceSearchDTO);
        List<BindCardDTO> bindCardDTOS = bindCardCached.hmGetBindCardInfoByDeviceNames(deviceNames);
        Map<String, BindCardDTO> bindCardDTOMap = null;
        if (!CollectionUtils.isEmpty(bindCardDTOS)) {
            bindCardDTOMap = bindCardDTOS.stream().collect(Collectors.toMap(BindCardDTO::getDeviceName, a -> a, (k1, k2) -> k1));
        }
        for (LocationDeviceVO locationDeviceVO : locationDeviceVOS) {
            String deviceName = locationDeviceVO.getDeviceName();
            LocationDeviceExcelVO locationDeviceExcelVO = new LocationDeviceExcelVO();
            BeanUtils.copyProperties(locationDeviceVO, locationDeviceExcelVO);
            Integer wearType = locationDeviceVO.getWearType();
            if (wearType != null) {
                locationDeviceExcelVO.setWearType(wearTypeMap.get(wearType));
            }
            BindCardDTO bindCardDTO = null;
            locationDeviceExcelVO.setBindCardState("未绑定");
            if (!CollectionUtils.isEmpty(bindCardDTOMap)) {
                bindCardDTO = bindCardDTOMap.get(deviceName);
                if (bindCardDTO != null) {
                    locationDeviceExcelVO.setBindCardState("已绑定");
                    locationDeviceExcelVO.setPersonnelName(bindCardDTO.getPersonnelName());
                    locationDeviceExcelVO.setIdCardNo(bindCardDTO.getIdCardNo());
                }
            }
            if (state != null) {
                locationDeviceExcelVO.setState(stateTypeMap.get(state));
            } else {
                //默认离线
                int tempState = NumericalConstants.TWO;
                if (!CollectionUtils.isEmpty(tagInfoMap)) {
                    HttpTagInfoVO httpTagInfoVO = tagInfoMap.get(deviceName);
                    if (httpTagInfoVO != null && httpTagInfoVO.getOnline()) {
                        tempState = NumericalConstants.ONE;
                    }
                }
                locationDeviceExcelVO.setState(stateTypeMap.get(tempState));
            }
            if (isReturn != null && isReturn) {
                locationDeviceExcelVO.setIsReturn("是");
            } else {
                if (bindCardDTO != null) {
                    Date bindTime = bindCardDTO.getBindTime();
                    locationDeviceExcelVO.setIsReturn("否");
                    //核电环境
                    if (systemFlag) {
                        Integer bindWay = bindCardDTO.getBindWay();
                        if (bindWay != null && bindWay.equals(NumericalConstants.TWO) && bindTime != null && bindTime.getTime() < dateTime) {
                            locationDeviceExcelVO.setIsReturn("是");
                        }
                    } else {
                        //公司测试环境
                        if (bindTime != null && bindTime.getTime() < dateTime) {
                            locationDeviceExcelVO.setIsReturn("是");
                        }
                    }
                }
            }
            LocationDevice locationDevice = locationDeviceCached.hgetLocationDeviceInfo(deviceName);
            if (locationDevice != null && StringUtils.isNotBlank(locationDevice.getPersonName())) {
                locationDeviceExcelVO.setPersonName(locationDevice.getPersonName());
            }
            locationDeviceExcelVOS.add(locationDeviceExcelVO);
        }
        return locationDeviceExcelVOS;
    }

    /**
     * 获取标签历史数据
     *
     * @return java.util.List<com.bsj.power.common.def.vo.pls.httpVo.HistoryOriginalVO>
     * @author ljx
     * @time 2024/5/25 9:47
     */
    @Override
    public List<HistoryOriginalVO> getTagHistoryData(TrackDTO trackDTO) throws ParseException {
        String startTime = trackDTO.getStartTime();
        String endTime = trackDTO.getEndTime();
        String locationDeviceId = trackDTO.getLocationDeviceId();
        ParamCheckUtil.isAnyBlank(startTime, endTime);
        if (DateUtils.compareDate(startTime, endTime)) {
            throw new ApiException(JsonResultEnum.PARAM_ERROR);
        }

        long sTime = DateUtils.strToDate(startTime).getTime();
        long eTime = DateUtils.strToDate(endTime).getTime();
        // 这里只用一个list的原因，把所有设备的轨迹信息合并在一起
        List<HistoryOriginalVO> historyOriginalVOS = new LinkedList<>();
        List<byte[]> listBytes = wrFileBaseUntil.readDataBytes(locationDeviceId, sTime, eTime);
        if (CollectionUtils.isEmpty(listBytes)) {
            return historyOriginalVOS;
        }
        for (byte[] bytes : listBytes) {
            String data = new String(bytes);
            HttpTagPosVO posData = JSON.parseObject(data, HttpTagPosVO.class);
            HistoryOriginalVO historyOriginalVo = new HistoryOriginalVO();
            //x,y,z
            double[] pos = posData.getPos();
            if (pos.length < 3) {
                continue;
            }
            historyOriginalVo.setDeviceName(locationDeviceId);
            historyOriginalVo.setPos(pos);
            historyOriginalVo.setTime(DateUntil.dateToDayStr(new Date(posData.getTime())));
            historyOriginalVo.setMapId(posData.getMapId());
//            if (trackDTO.getLocationDeviceId() != null) {
//                historyOriginalVo.setPersonnelName(trackDTO.getLocationDeviceId());
//            }
            if (trackDTO.getPersonnelName() != null) {
                historyOriginalVo.setPersonnelName(trackDTO.getPersonnelName());
            }
            if (trackDTO.getEmpNo() != null) {
                historyOriginalVo.setEmpNo(trackDTO.getEmpNo());
            }
            if (trackDTO.getClassify() != null) {
                historyOriginalVo.setClassify(trackDTO.getClassify());
            }

            historyOriginalVOS.add(historyOriginalVo);
        }


        return historyOriginalVOS.stream()
                .collect(Collectors.collectingAndThen(Collectors.toMap(HistoryOriginalVO::getTime
                        , event -> event, (e1, e2) -> e1), map -> map.values().stream()
                        .sorted(Comparator.comparing(HistoryOriginalVO::getTime)).collect(Collectors.toList())));
    }


//    /**
//     * 获取标签历史数据
//     *
//     * @param trackDTO
//     * @return java.util.List<com.bsj.power.common.def.vo.pls.httpVo.HistoryOriginalVO>
//     * @author ljx
//     * @time 2024/5/25 9:47
//     */
//    @Override
//    public List<HistoryOriginalVO> getTagHistoryData2(TrackDTO trackDTO) throws ParseException {
//        String startTime = trackDTO.getStartTime();
//        String endTime = trackDTO.getEndTime();
//        Integer type = trackDTO.getType();
//        String content = trackDTO.getContent();
//        ParamCheckUtil.isAnyBlank(startTime, endTime);
//        if (DateUtils.compareDate(startTime, endTime)) {
//            throw new ApiException(JsonResultEnum.PARAM_ERROR);
//        }
//        Date endDate = DateUtils.strToDate(endTime);
//        // 三天的时间戳，把查询绑卡时间和退卡时间分别往前加三天和往后加三天
//        long threeDayMillions = 60 * 1000 * 60 * 24 * 3;
//        long before = DateUtils.strToDate(startTime).getTime() - threeDayMillions;
//        long after = DateUtils.strToDate(endTime).getTime() + threeDayMillions;
//        //获取该人员时间范围内所绑定的卡；一个人员同一时间只能绑一个卡，所以查询出来的时间、绑卡退卡顺序一定是正确的
//        List<CardReport> cardReports = cardReportMapper.selectList(Wrappers.<CardReport>lambdaQuery()
//                .eq(CardReport::getEmpNo, content).between(CardReport::getCreateTime, new Date(before), new Date(after)));
//        if (!CollectionUtils.isEmpty(cardReports)) {
//            // 这里把绑卡信息归类整理，多条整理为一条
//            int size = cardReports.size();
//            CardReport cardReport = cardReports.get(NumericalConstants.ZERO);
//            //只有一条并且为绑卡状态的情况
//            if (size == NumericalConstants.ONE) {
//                if (cardReport.getType().equals(NumericalConstants.ONE)) {
//                    cardReport.setEndTime(endDate);
//                } else {
//                    cardReports.remove(cardReport);
//                }
//            } else {
//                int temp;
//                for (int i = 0; i < cardReports.size(); i += temp) {
//                    CardReport tempCardReport = cardReports.get(i);
//                    //如果第一条为退卡则删除
//                    if (i == NumericalConstants.ZERO && tempCardReport.getType().equals(NumericalConstants.TWO)) {
//                        cardReports.remove(i);
//                        temp = NumericalConstants.ZERO;
//                    } else if (i == cardReports.size() - NumericalConstants.ONE) {
//                        //最后一条为绑卡则设置结束时间
//                        tempCardReport.setEndTime(endDate);
//                        temp = NumericalConstants.ONE;
//                    } else {
//                        tempCardReport.setEndTime(cardReports.get(i + NumericalConstants.ONE).getCreateTime());
//                        cardReports.remove(i + NumericalConstants.ONE);
//                        temp = NumericalConstants.ONE;
//                    }
//                }
//            }
//        }
//
//        long sTime = DateUtils.strToDate(startTime).getTime();
//        long eTime = DateUtils.strToDate(endTime).getTime();
//        // 先查询轨迹，再查询绑卡的人员信息
//        List<String> locationDeviceIds = new ArrayList<>();
//        if (type == 1) {
//            locationDeviceIds.add(content);
//        } else if (type == 2) {
//            if (!CollectionUtils.isEmpty(cardReports)) {
//                List<String> collect = cardReports.stream().map(CardReport::getDeviceName).distinct().collect(Collectors.toList());
//                locationDeviceIds.addAll(collect);
//            }
//        }
//        if (CollectionUtils.isEmpty(locationDeviceIds)) {
//            throw new ApiException(JsonResultEnum.FAIL, "没有查询到对应的定位设备信息，无法查询");
//        }
//        List<String> distinct = locationDeviceIds.stream().distinct().collect(Collectors.toList());
//        // 这里只用一个list的原因，把所有设备的轨迹信息合并在一起
//        List<HistoryOriginalVO> historyOriginalVOS = new LinkedList<>();
//        for (String locationDeviceId : distinct) {
//            List<byte[]> listBytes = wrFileBaseUntil.readDataBytes(locationDeviceId, sTime, eTime);
//            if (listBytes == null || listBytes.size() == 0) {
//                continue;
//            }
//            for (byte[] bytes : listBytes) {
//                String data = new String(bytes);
//                HttpTagPosVO posData = JSON.parseObject(data, HttpTagPosVO.class);
//                HistoryOriginalVO historyOriginalVo = new HistoryOriginalVO();
//                //x,y,z
//                double[] pos = posData.getPos();
//                if (pos.length < 3) {
//                    continue;
//                }
//                historyOriginalVo.setDeviceName(locationDeviceId);
//                historyOriginalVo.setPos(pos);
//                historyOriginalVo.setTime(DateUntil.dateToDayStr(new Date(posData.getTime())));
//                historyOriginalVo.setMapId(posData.getMapId());
//                if (!CollectionUtils.isEmpty(cardReports) && type == 2) {
//                    for (CardReport report : cardReports) {
//                        if (!report.getEmpNo().equals(content)) {
//                            continue;
//                        }
//                        long createTimeMillions = report.getCreateTime().getTime();
//                        long endTimeMillions = report.getEndTime().getTime();
//                        long time1 = DateUtils.strToDate(historyOriginalVo.getTime()).getTime();
//                        if (time1 >= createTimeMillions && time1 <= endTimeMillions) {
//                            historyOriginalVo.setPersonnelName(report.getPersonnelName());
//                            historyOriginalVo.setEmpNo(report.getEmpNo());
//                            historyOriginalVo.setClassify(report.getClassify());
//                        }
//                    }
//                }
//
//                historyOriginalVOS.add(historyOriginalVo);
//            }
//        }
//        return historyOriginalVOS.stream()
//                .collect(Collectors.collectingAndThen(Collectors.toMap(HistoryOriginalVO::getTime
//                        , event -> event, (e1, e2) -> e1), map -> map.values().stream()
//                        .sorted(Comparator.comparing(HistoryOriginalVO::getTime)).collect(Collectors.toList())));
//
//    }


    @Override
    public JsonResult getLastPosition(String time, Integer jobId) {
        JsonResult jsonResult = new JsonResult();
        Job job = jobMapper.selectById(jobId);
        if (job == null) {
            jsonResult.setCode(-1);
            jsonResult.setMsg("工单号错误");
            return jsonResult;
        }
        Date date = DateUtils.strToDate(time);
        long dateTime = date.getTime();
        // 设置查询时间为前后一个小时
        long timeBefore;
        long oneHourMillions = 60 * 60 * 1000;
        long sTime = dateTime - oneHourMillions;
        long eTime = dateTime + oneHourMillions;

        // 三天的时间戳，把查询绑卡时间和退卡时间分别往前加三天和往后加三天
        long threeDayMillions = 60 * 1000 * 60 * 24 * 3;
        long before = DateUtils.strToDate(time).getTime() - threeDayMillions;
        long after = DateUtils.strToDate(time).getTime() + threeDayMillions;

        Date endDate = new Date(eTime);

        // 查询负责人和作业人员的工号
        ArrayList<String> empNos = new ArrayList<>();

        // 获取负责人的工号
        String directorId = job.getDirectorId();
        QueryWrapper<Personnel> personnelQueryWrapper = new QueryWrapper<>();
        personnelQueryWrapper.eq("director_id", directorId);
        Personnel personnel = personnelMapper.selectOne(personnelQueryWrapper);
        if (personnel != null) {
            empNos.add(personnel.getEmpNo());
        }

        // 获取作业人员的工号，先根据工单和作业人员绑定关系查作业人员id，再根据作业人员id查作业人员获取工号
        QueryWrapper<JobPersonnel> jobPersonnelQueryWrapper = new QueryWrapper<>();
        jobPersonnelQueryWrapper.eq("job_id", jobId);
        List<JobPersonnel> jobPersonnels = jobPersonnelMapper.selectList(jobPersonnelQueryWrapper);
        if (jobPersonnels.size() != 0) {
            List<Integer> workPersonelIds = jobPersonnels.stream().map(JobPersonnel::getPersonnelId).distinct().collect(Collectors.toList());
            QueryWrapper<WorkPersonnel> workPersonnelQueryWrapper = new QueryWrapper<>();
            workPersonnelQueryWrapper.in("work_personnel_id", workPersonelIds);
            List<WorkPersonnel> workPersonnels = workPersonnelMapper.selectList(workPersonnelQueryWrapper);
            if (workPersonnels.size() != 0) {
                empNos.addAll(workPersonnels.stream().map(WorkPersonnel::getTemporaryEmpNo).distinct().collect(Collectors.toList()));
            }
        }

        if (empNos.size() == 0) {
            jsonResult.setCode(-1);
            jsonResult.setMsg("该工单没有绑定人员信息，无法查询");
            return jsonResult;
        }

        // 定位设备设备号列表
        List<String> locationDeviceIds = new ArrayList<>();
        // 根据所有人员的工号查询绑卡信息
        QueryWrapper<CardReport> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("emp_no", empNos);
        queryWrapper.between("create_time", new Date(before), new Date(after));
        List<CardReport> cardReports = cardReportMapper.selectList(queryWrapper);
        if (CollectionUtils.isEmpty(cardReports)) {
            jsonResult.setCode(-1);
            jsonResult.setMsg("近期没有绑卡信息，无法查询");
            return jsonResult;
        } else {
            List<String> deviceNames = cardReports.stream().map(CardReport::getDeviceName).distinct().collect(Collectors.toList());
            locationDeviceIds.addAll(deviceNames);
        }
        // 这里把绑卡信息归类整理，多条整理为一条
        int size = cardReports.size();
        CardReport cardReport = cardReports.get(NumericalConstants.ZERO);
        //只有一条并且为绑卡状态的情况
        if (size == NumericalConstants.ONE) {
            if (cardReport.getType().equals(NumericalConstants.ONE)) {
                cardReport.setEndTime(endDate);
            } else {
                cardReports.remove(cardReport);
            }
        } else {
            int temp;
            for (int i = 0; i < cardReports.size(); i += temp) {
                CardReport tempCardReport = cardReports.get(i);
                //如果第一条为退卡则删除
                if (i == NumericalConstants.ZERO && tempCardReport.getType().equals(NumericalConstants.TWO)) {
                    cardReports.remove(i);
                    temp = NumericalConstants.ZERO;
                } else if (i == cardReports.size() - NumericalConstants.ONE) {
                    //最后一条为绑卡则设置结束时间
                    tempCardReport.setEndTime(endDate);
                    temp = NumericalConstants.ONE;
                } else {
                    tempCardReport.setEndTime(cardReports.get(i + NumericalConstants.ONE).getCreateTime());
                    cardReports.remove(i + NumericalConstants.ONE);
                    temp = NumericalConstants.ONE;
                }
            }
        }

        // 这里只用一个list的原因，把所有设备的轨迹信息合并在一起
        List<HistoryOriginalVO> historyOriginalVOS = new LinkedList<>();
        for (String locationDeviceId : locationDeviceIds) {

            List<byte[]> listBytes = wrFileBaseUntil.readDataBytes(locationDeviceId, sTime, eTime);
            if (listBytes == null || listBytes.size() == 0) {
                continue;
            }
            for (byte[] bytes : listBytes) {
                String data = new String(bytes);
                HttpTagPosVO posData = JSON.parseObject(data, HttpTagPosVO.class);
                HistoryOriginalVO historyOriginalVo = new HistoryOriginalVO();
                //x,y,z
                double[] pos = posData.getPos();
                if (pos.length < 3) {
                    continue;
                }
                historyOriginalVo.setMapId(posData.getMapId());
                historyOriginalVo.setDeviceName(locationDeviceId);
                historyOriginalVo.setPos(pos);
                historyOriginalVo.setTime(DateUntil.dateToDayStr(new Date(posData.getTime())));

                for (CardReport report : cardReports) {
                    if (!report.getDeviceName().equals(locationDeviceId)) {
                        continue;
                    }
                    long createTimeMillions = report.getCreateTime().getTime();
                    long endTimeMillions = report.getEndTime().getTime();
                    long time1 = DateUtils.strToDate(historyOriginalVo.getTime()).getTime();
                    if (time1 >= createTimeMillions && time1 <= endTimeMillions) {
                        historyOriginalVo.setPersonnelName(report.getPersonnelName());
                        historyOriginalVo.setEmpNo(report.getEmpNo());
                        historyOriginalVo.setClassify(report.getClassify());
                    }
                }

                historyOriginalVOS.add(historyOriginalVo);
            }
        }

        if (CollectionUtils.isEmpty(historyOriginalVOS)) {
            jsonResult.setCode(-1);
            jsonResult.setMsg("近期没有位置数据，无法查询");
            return jsonResult;
        }

        List<HistoryOriginalVO> result = new ArrayList<>();

        List<HistoryOriginalVO> personnelNameList = historyOriginalVOS.stream()
                .filter(historyOriginalVO -> historyOriginalVO.getPersonnelName() != null)
                .collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(personnelNameList)) {
            Map<String, List<HistoryOriginalVO>> listMap = personnelNameList.stream().collect(Collectors.groupingBy(HistoryOriginalVO::getPersonnelName));
            if (!CollectionUtils.isEmpty(listMap)) {
                Set<Map.Entry<String, List<HistoryOriginalVO>>> entries = listMap.entrySet();
                for (Map.Entry<String, List<HistoryOriginalVO>> entry : entries) {
                    List<HistoryOriginalVO> collect = entry.getValue().stream().filter(hvo
                            -> DateUtils.strToDate(hvo.getTime()).getTime() < DateUtils.strToDate(time).getTime()).collect(Collectors.toList());
                    if (!CollectionUtils.isEmpty(collect)) {
                        HistoryOriginalVO historyOriginalVO = collect.stream().
                                sorted(Comparator.comparing(HistoryOriginalVO::getTime).reversed()).collect(Collectors.toList()).get(0);
                        result.add(historyOriginalVO);
                    }
                }
            }
        }
        if (CollectionUtils.isEmpty(result)) {
            jsonResult.setCode(-1);
            jsonResult.setMsg("该时间段之前没有定位数据，请重新查询");
            return jsonResult;
        }

        jsonResult.setCode(JsonResultEnum.SUCCESS.getCode());
        jsonResult.setMsg(JsonResultEnum.SUCCESS.getMsg());
        jsonResult.setData(result);

        return jsonResult;

    }

    /**
     * 根据工号获取人员信息与工单信息
     *
     * @param empNo
     * @return com.bsj.power.common.def.vo.PersonAndJobVO
     * @author ljx
     * @time 2024/9/14 19:40
     */
    @Override
    public PersonAndJobVO getPersonAndJobInfo(String empNo) {
        PersonAndJobVO personAndJobVO = new PersonAndJobVO();
        ParamCheckUtil.isNull(empNo);
        Personnel personnel = personnelMapper.selectOne(Wrappers.<Personnel>lambdaQuery().eq(Personnel::getEmpNo, empNo));
        WorkPersonnel workPersonnel = workPersonnelMapper.selectOne(Wrappers.<WorkPersonnel>lambdaQuery().eq(WorkPersonnel::getTemporaryEmpNo, empNo));
        if (personnel == null && workPersonnel == null) {
            return personAndJobVO;
        }
        List<Job> jobs = null;
        String dateOfBirth = null;
        Date date = new Date();
        if (personnel != null) {
            PersonnelVO personnelVO = new PersonnelVO();
            BeanUtils.copyProperties(personnel, personnelVO);
            dateOfBirth = personnel.getDateOfBirth();
            if (StringUtils.isNotBlank(dateOfBirth)) {
                personnelVO.setAge(getAgeByDate(dateOfBirth));
            }
            personAndJobVO.setPersonnelVO(personnelVO);
            personAndJobVO.setPersonType(NumericalConstants.ONE);
            jobs = jobMapper.selectList(Wrappers.<Job>lambdaQuery().le(Job::getStartTime, date)
                    .ge(Job::getEndTime, date).eq(Job::getDirectorId, personnel.getDirectorId()));
            if (!CollectionUtils.isEmpty(jobs)) {
                personAndJobVO.setJobNames(jobs.stream().map(Job::getDescription).collect(Collectors.toList()));
            }
        } else {
            WorkPersonnelVO workPersonnelVO = new WorkPersonnelVO();
            BeanUtils.copyProperties(workPersonnel, workPersonnelVO);
            workPersonnelVO.setAge(getAgeByIdCodeNo(workPersonnelVO.getIdCardNo()));
            personAndJobVO.setWorkPersonnelVO(workPersonnelVO);
            personAndJobVO.setPersonType(NumericalConstants.TWO);
            List<JobPersonnel> jobPersonnelList = jobPersonnelMapper.selectList(Wrappers.<JobPersonnel>lambdaQuery()
                    .eq(JobPersonnel::getPersonnelId, workPersonnel.getWorkPersonnelId()));
            if (!CollectionUtils.isEmpty(jobPersonnelList)) {
                List<Long> jobIds = jobPersonnelList.stream().map(JobPersonnel::getJobId).collect(Collectors.toList());
                jobs = jobMapper.selectList(Wrappers.<Job>lambdaQuery().le(Job::getStartTime, date)
                        .ge(Job::getEndTime, date).in(Job::getJobId, jobIds));
                if (!CollectionUtils.isEmpty(jobs)) {
                    personAndJobVO.setJobNames(jobs.stream().map(Job::getDescription).collect(Collectors.toList()));
                }
            }
        }
        return personAndJobVO;
    }


    /**
     * 获取定位信息
     *
     * @param deviceName
     * @return com.bsj.power.common.def.vo.pls.PosInfoVO
     * @author ljx
     * @time 2024/6/5 12:05
     */
    @Override
    public PosInfoVO getPosInfo(String deviceName) {
        PosInfoVO posInfoVO = new PosInfoVO();
        ParamCheckUtil.isBlank(deviceName);
        LocationDevice locationDevice = locationDeviceCached.hgetLocationDeviceInfo(deviceName);
        if (locationDevice == null) {
            return posInfoVO;
        }
        //状态
        String url = locationDevice.getDeviceType().equals(NumericalConstants.ONE) ? ApiConstants.GET_ALL_ANCHOR : ApiConstants.GET_ALL_TAG;
        List<HttpTagInfoVO> httpTagInfoVOS = getDeviceInfo(deviceName, url);
        if (!CollectionUtils.isEmpty(httpTagInfoVOS)) {
            HttpTagInfoVO httpTagInfoVO = httpTagInfoVOS.get(NumericalConstants.ZERO);
            posInfoVO.setOnline(httpTagInfoVO.getOnline());
        } else {
            posInfoVO.setOnline(false);
        }
        //位置信息
        String str = jedisClusterBSJ.get(UWBPosConstant.REDIS_TAG_POS_KEY + deviceName);
        if (StringUtils.isNotBlank(str)) {
            posInfoVO.setHttpTagPosVO(JSONObject.parseObject(str, HttpTagPosVO.class));
        }
        return posInfoVO;
    }

    /**
     * 获取轨迹查询参数
     *
     * @param deviceName
     * @param personnelName
     * @param startTime
     * @param endTime
     * @return java.util.List<com.bsj.power.common.def.entity.cardReport.CardReport>
     * @author ljx
     * @time 2024/5/27 11:25
     */
    private List<CardReport> getQueryParam(String deviceName, String personnelName, String startTime, String endTime) {
        Date startDate = DateUtils.strToDate(startTime);
        Date endDate = DateUtils.strToDate(endTime);
//        List<CardReport> cardReports = new LinkedList<>();
        ParamCheckUtil.isBlank(deviceName);
//        if (StringUtils.isNotBlank(deviceName)) {
//            cardReports.add(new CardReport(deviceName, startDate, endDate));
//        } else if (StringUtils.isNotBlank(personnelName)) {
        //获取该人员时间范围内所绑定的卡；一个人员同一时间只能绑一个卡，所以查询出来的时间、绑卡退卡顺序一定是正确的
        List<CardReport> cardReports = cardReportMapper.selectList(Wrappers.<CardReport>lambdaQuery().eq(CardReport::getDeviceName, deviceName).between(CardReport::getCreateTime, startTime, endTime));
        if (!CollectionUtils.isEmpty(cardReports)) {
            int size = cardReports.size();
            CardReport cardReport = cardReports.get(NumericalConstants.ZERO);
            //只有一条并且为绑卡状态的情况
            if (size == NumericalConstants.ONE) {
                if (cardReport.getType().equals(NumericalConstants.ONE)) {
                    cardReport.setEndTime(endDate);
                } else {
                    cardReports.remove(cardReport);
                }
            } else {
                int temp;
                for (int i = 0; i < cardReports.size(); i += temp) {
                    CardReport tempCardReport = cardReports.get(i);
                    //如果第一条为退卡则删除
                    if (i == NumericalConstants.ZERO && tempCardReport.getType().equals(NumericalConstants.TWO)) {
                        cardReports.remove(i);
                        temp = NumericalConstants.ZERO;
                    } else if (i == cardReports.size() - NumericalConstants.ONE) {
                        //最后一条为绑卡则设置结束时间
                        tempCardReport.setEndTime(endDate);
                        temp = NumericalConstants.ONE;
                    } else {
                        tempCardReport.setEndTime(cardReports.get(i + NumericalConstants.ONE).getCreateTime());
                        cardReports.remove(i + NumericalConstants.ONE);
                        temp = NumericalConstants.ONE;
                    }
                }
            }
        }
//        } else {
//            throw new ApiException(JsonResultEnum.PARAM_ERROR);
//        }
        return cardReports;
    }

    /**
     * 获取当前作业是哪些
     *
     * @param personnelId
     * @return java.util.List<java.lang.Long>
     * @author ljx
     * @time 2024/5/9 11:07
     */
    private List<Long> getPresentJob(Integer personnelId) {
        PersonnelSearchDTO personnelSearchDTO = new PersonnelSearchDTO();
        personnelSearchDTO.setPersonnelId(personnelId);
        Date date = new Date();
        personnelSearchDTO.setStartTime(DateUtils.getStartOfDay2(date));
        personnelSearchDTO.setEndTime(DateUtils.getEndOfDay2(date));
        return jobPersonnelMapper.getPresentJob(personnelSearchDTO);
    }

    /**
     * 设备类型转换
     *
     * @param deviceType
     * @return java.lang.String
     * @author ljx
     * @time 2024/5/14 14:20
     */
    public static String deviceTypeToStr(Integer deviceType) {
        String resul = "";
        switch (deviceType) {
            case 1:
                resul = "基站";
                break;
            case 2:
                resul = "UWB";
                break;
            case 3:
                resul = "UWB+北斗";
                break;
            default:
                log.info("错误的设备类型{}", deviceType);
                break;
        }
        return resul;
    }

    /**
     * 获取设备信息
     *
     * @param deviceName
     * @param url
     * @return java.util.List<com.bsj.power.common.def.vo.pls.httpVo.HttpTagInfoVO>
     * @author ljx
     * @time 2024/5/28 19:27
     */
    private List<HttpTagInfoVO> getDeviceInfo(String deviceName, String url) {
        List<HttpTagInfoVO> httpTagInfoVOS = null;
        log.info("请求路径{}", ipHost + url);
        try {
            String str = HttpUtil.get(ipHost + url, 3000);
            if (StringUtils.isNotBlank(str)) {
                JSONObject result = JSONObject.parseObject(str);
                if (result.getInteger("code").equals(JsonResultEnum.SUCCESS.getCode())) {
                    JSONArray jsonArray = result.getJSONArray("data");
                    if (!CollectionUtils.isEmpty(jsonArray)) {
                        httpTagInfoVOS = jsonArray.toJavaList(HttpTagInfoVO.class);
                    }
                }
            }
            if (!CollectionUtils.isEmpty(httpTagInfoVOS) && StringUtils.isNotBlank(deviceName)) {
                httpTagInfoVOS = httpTagInfoVOS.stream().filter(httpTagInfoVO -> httpTagInfoVO.getSn().equals(deviceName)).collect(Collectors.toList());
            }
        } catch (Exception e) {
            log.error("公司测试环境无法请求该地址..........");
        }
        return httpTagInfoVOS;
    }

    /**
     * 基站设备树结构
     *
     * @return java.util.List<com.bsj.power.common.def.vo.tree.TreeStructureVO>
     * @author ljx
     * @time 2024/10/7 11:38
     */
    @Override
    public List<TreeStructureVO> getTreeStructureVO() {
        List<TreeStructureVO> treeStructureVOS = new ArrayList<>();
        List<Tree> trees = treeMapper.selectList(null);
        List<TreeStructureVO> treeStructureVOList = structuralConstruction(trees);
        if (!CollectionUtils.isEmpty(treeStructureVOList)) {
            treeStructureVOS.addAll(treeStructureVOList);
        }
        return treeStructureVOS;
    }

    /**
     * 基站设备信息导出
     *
     * @param locationDeviceSearchDTO
     * @return java.util.List<com.bsj.power.common.def.vo.pls.excel.AnchorDeviceExcelVO>
     * @author ljx
     * @time 2024/10/24 16:35
     */
    @Override
    public List<AnchorDeviceExcelVO> getAnchorExportData(LocationDeviceSearchDTO locationDeviceSearchDTO) {
        Map<String, HttpTagInfoVO> tagInfoMap = new HashMap<>();
        List<String> deviceNames = null;
        //TODO 此处参数处理需区分环境
        if (systemFlag) {
            deviceNames = paramHandleOne(locationDeviceSearchDTO, tagInfoMap, null);
        } else {
            deviceNames = paramHandleTwo(locationDeviceSearchDTO, tagInfoMap, null);
        }
        List<AnchorDeviceExcelVO> anchorDeviceExcelVOS = new LinkedList<>();
        if (CollectionUtils.isEmpty(deviceNames)) {
            return anchorDeviceExcelVOS;
        }
        Integer state = locationDeviceSearchDTO.getState();
        locationDeviceSearchDTO.setDeviceNames(deviceNames);
        Integer treeId = locationDeviceSearchDTO.getTreeId();
        if (treeId != null) {
            List<Integer> treeIds = treeService.getTreeIds(treeId, NumericalConstants.TWO);
            locationDeviceSearchDTO.setTreeIds(treeIds);
        }
        locationDeviceSearchDTO.setSearchType(NumericalConstants.TWO);
        List<LocationDeviceVO> locationDeviceVOS = locationDeviceMapper.pageLocationDevice(locationDeviceSearchDTO);
        for (LocationDeviceVO locationDeviceVO : locationDeviceVOS) {
            AnchorDeviceExcelVO anchorDeviceExcelVO = new AnchorDeviceExcelVO();
            BeanUtils.copyProperties(locationDeviceVO, anchorDeviceExcelVO);
            anchorDeviceExcelVO.setDeviceType(deviceTypeToStr(locationDeviceVO.getDeviceType()));
            if (state != null) {
                anchorDeviceExcelVO.setState(stateTypeMap.get(state));
            } else {
                //默认离线
                int tempState = NumericalConstants.TWO;
                if (!CollectionUtils.isEmpty(tagInfoMap)) {
                    HttpTagInfoVO httpTagInfoVO = tagInfoMap.get(locationDeviceVO.getDeviceName());
                    if (httpTagInfoVO != null && httpTagInfoVO.getOnline()) {
                        tempState = NumericalConstants.ONE;
                    }
                }
                anchorDeviceExcelVO.setState(stateTypeMap.get(tempState));
            }
            anchorDeviceExcelVOS.add(anchorDeviceExcelVO);
        }
        return anchorDeviceExcelVOS;
    }

    /**
     * 设置基站二维信息
     *
     * @param locationDevice2DDTOS
     * @return com.bsj.power.common.config.global.JsonResult
     * @author ljx
     * @time 2024/10/29 10:21
     */
    @Override
    @Transactional
    public JsonResult setAnchor2DInfo(List<LocationDevice2DDTO> locationDevice2DDTOS) {
        ParamCheckUtil.isEmpty(locationDevice2DDTOS);
        locationDevice2DDTOS.forEach(locationDevice2DDTO -> {
            String deviceName = locationDevice2DDTO.getDeviceName();
            ParamCheckUtil.isBlank(deviceName);
            ParamCheckUtil.isNull(locationDeviceCached.hgetLocationDeviceInfo(deviceName));
        });
        locationDeviceMapper.setAnchor2DInfo(locationDevice2DDTOS);
        //修改缓存
        locationDevice2DDTOS.forEach(locationDevice2DDTO -> {
            LocationDevice locationDeviceInfo = locationDeviceCached.hgetLocationDeviceInfo(locationDevice2DDTO.getDeviceName());
            if (locationDeviceInfo != null) {
                locationDeviceInfo.setPointJson2d(locationDevice2DDTO.getPointJson2d());
                locationDeviceInfo.setFloor(locationDevice2DDTO.getFloor());
                locationDeviceInfo.setBuilding(locationDevice2DDTO.getBuilding());
                locationDeviceCached.hsetLocationDeviceInfo(locationDeviceInfo);
            }
        });
        return JsonResult.success();
    }

    /**
     * 根据栋数和楼层查询基站设备二维信息
     *
     * @param building
     * @param floor
     * @return com.bsj.power.common.def.vo.pls.AnchorDevice2DVO
     * @author ljx
     * @time 2024/10/29 11:13
     */
    @Override
    public AnchorDevice2DVO listDevice2DInfo(Integer building, Integer floor) {
        ParamCheckUtil.isNull(building);
        ParamCheckUtil.isNull(floor);
        List<HttpTagInfoVO> httpTagInfoVOS = getDeviceInfo(null, ApiConstants.GET_ALL_ANCHOR);
        Map<String, HttpTagInfoVO> httpTagInfoVOMap = null;
        if (!CollectionUtils.isEmpty(httpTagInfoVOS)) {
            httpTagInfoVOMap = httpTagInfoVOS.stream().collect(Collectors.toMap(HttpTagInfoVO::getSn, a -> a, (k1, k2) -> k1));
        }
        Integer totalCount = NumericalConstants.ZERO;
        Integer onlineCount = NumericalConstants.ZERO;
        Integer offlineCount = NumericalConstants.ZERO;
        List<Anchor2DInfoVO> anchor2DInfoVOS = locationDeviceMapper.listDevice2DInfo(building, floor);
        if (!CollectionUtils.isEmpty(anchor2DInfoVOS)) {
            for (Anchor2DInfoVO anchor2DInfoVO : anchor2DInfoVOS) {
                //默认离线
                boolean isOnline = false;
                if (!CollectionUtils.isEmpty(httpTagInfoVOMap)) {
                    HttpTagInfoVO httpTagInfoVO = httpTagInfoVOMap.get(anchor2DInfoVO.getDeviceName());
                    if (httpTagInfoVO != null && httpTagInfoVO.getOnline()) {
                        onlineCount++;
                        isOnline = true;
                    } else {
                        offlineCount++;
                    }
                } else {
                    offlineCount++;
                }
                anchor2DInfoVO.setIsOnline(isOnline);
            }
            totalCount = anchor2DInfoVOS.size();
        }
        AnchorDevice2DVO anchorDevice2DVO = new AnchorDevice2DVO(anchor2DInfoVOS, totalCount, onlineCount, offlineCount);
        return anchorDevice2DVO;
    }

    /**
     * 清除基站二维信息
     *
     * @param deviceNames
     * @return com.bsj.power.common.config.global.JsonResult
     * @author ljx
     * @time 2024/10/29 14:19
     */
    @Override
    @Transactional
    public JsonResult cleanAnchor2DInfo(String[] deviceNames) {
        if (deviceNames == null || deviceNames.length == NumericalConstants.ZERO) {
            return JsonResult.fail(JsonResultEnum.PARAM_ERROR);
        }
        List<String> list = Arrays.asList(deviceNames);
        locationDeviceMapper.cleanAnchor2DInfo(list);
        list.forEach(deviceName -> {
            LocationDevice locationDevice = locationDeviceCached.hgetLocationDeviceInfo(deviceName);
            if (locationDevice != null) {
                locationDevice.setPointJson2d(null);
                locationDevice.setFloor(null);
                locationDevice.setBuilding(null);
                locationDeviceCached.hsetLocationDeviceInfo(locationDevice);
            }
        });
        return JsonResult.success();
    }

    /**
     * 设置设备别名
     *
     * @param file
     * @return com.bsj.power.common.config.global.JsonResult
     * @author ljx
     * @time 2024/10/29 16:07
     */
    @Override
    @Transactional
    public JsonResult setNikeName(MultipartFile file) throws IOException {
        //文件校验
        if (file == null || file.getSize() <= 0) {
            return JsonResult.fail(JsonResultEnum.PARAM_ERROR);
        }
        String filename = file.getOriginalFilename();
        String fileType = filename.substring(filename.lastIndexOf("."));
        // 文件格式校验
        if (!".xlsx".equals(fileType)) {
            return JsonResult.fail(JsonResultEnum.PARAM_ERROR);
        }
        //解析文件获取数据
        ModelExcelListener listener = new ModelExcelListener();
        InputStream inputStream = file.getInputStream();
        EasyExcel.read(inputStream, LocationDeviceTemplate.class, listener).sheet().doRead();
        Map<Integer, LocationDeviceTemplate> dataList = listener.getDatas();
        if (CollectionUtils.isEmpty(dataList)) {
            return JsonResult.fail(JsonResultEnum.PARAM_ERROR);
        }
        List<LocationDeviceTemplate> deviceTemplates = dataList.values().stream().collect(Collectors.toList());
        if (CollectionUtils.isEmpty(deviceTemplates)) {
            return JsonResult.fail(JsonResultEnum.PARAM_ERROR);
        }
        locationDeviceMapper.batchSetNikeName(deviceTemplates);
        deviceTemplates.forEach(deviceTemplate -> {
            LocationDevice locationDevice = locationDeviceCached.hgetLocationDeviceInfo(deviceTemplate.getDeviceName());
            if (locationDevice != null) {
                locationDevice.setOtherName(deviceTemplate.getOtherName());
                locationDeviceCached.hsetLocationDeviceInfo(locationDevice);
            }
        });
        return JsonResult.success();
    }

    /**
     * 标签设备是否锁定
     *
     * @param deviceName 设备号
     * @param isLockIn   是否锁定 1是 2否
     * @return com.bsj.power.common.config.global.JsonResult
     * @author ljx
     * @time 2024/12/6 10:50
     */
    @Override
    @Transactional
    public JsonResult isLockIn(String deviceName, Integer isLockIn) {
        ParamCheckUtil.isNull(isLockIn);
        ParamCheckUtil.isBlank(deviceName);
        if (!isLockIn.equals(NumericalConstants.ONE) && !isLockIn.equals(NumericalConstants.TWO)) {
            return JsonResult.fail(JsonResultEnum.PARAM_ERROR);
        }
        LocationDevice locationDevice = locationDeviceMapper.selectOne(Wrappers.<LocationDevice>lambdaQuery().eq(LocationDevice::getDeviceName, deviceName));
        ParamCheckUtil.isNull(locationDevice);
        if (locationDevice.getDeviceType().equals(NumericalConstants.ONE)) {
            return JsonResult.fail(JsonResultEnum.PARAM_ERROR);
        }
        if (isLockIn.equals(NumericalConstants.ONE)) {
            BindCardDTO bindCardDTO = bindCardCached.hgetBindCardInfo(RedisConstant.BIND_CARD_REDIS_DEVICE_NAME_KEY + deviceName);
            if (bindCardDTO != null) {
                return JsonResult.fail(JsonResultEnum.LOCATION_DEVICE_ALREADY_BIND);
            }
        }
        locationDevice.setIsLockIn(isLockIn);
        if (locationDeviceMapper.updateById(locationDevice) > NumericalConstants.ZERO) {
            locationDeviceCached.hsetLocationDeviceInfo(locationDevice);
            return JsonResult.success();
        } else {
            return JsonResult.fail();
        }
    }

    /**
     * 搭建树结构
     *
     * @param treeList
     * @return java.util.List<com.bsj.power.common.def.vo.SceneTreeVO>
     * @author ljx
     * @time 2024/10/7 11:44
     */
    private List<TreeStructureVO> structuralConstruction(List<Tree> treeList) {
        if (CollectionUtils.isEmpty(treeList)) {
            return null;
        }
        //统计出每个场景下有多少个基站
        List<Integer> treeIds = treeList.stream().map(Tree::getTreeId).collect(Collectors.toList());
        List<LocationDevice> locationDevices = locationDeviceMapper.selectList(Wrappers.<LocationDevice>lambdaQuery()
                .eq(LocationDevice::getDeviceType, NumericalConstants.ONE).in(LocationDevice::getTreeId, treeIds));
        Map<Integer, List<LocationDevice>> locationDeviceMap = null;
        if (!CollectionUtils.isEmpty(locationDevices)) {
            locationDeviceMap = locationDevices.stream().collect(Collectors.groupingBy(LocationDevice::getTreeId));
        }
        //基站设备
        List<HttpTagInfoVO> httpTagInfoVOS = getDeviceInfo(null, ApiConstants.GET_ALL_ANCHOR);
        Map<String, HttpTagInfoVO> tagInfoVOMap = null;
        if (!CollectionUtils.isEmpty(httpTagInfoVOS)) {
            tagInfoVOMap = httpTagInfoVOS.stream().collect(Collectors.toMap(HttpTagInfoVO::getSn, Function.identity()));
        }
        //类型转换
        Map<Integer, TreeStructureVO> treeStructureVOMap = treeList.stream().map(tree -> {
            TreeStructureVO treeStructureVO = new TreeStructureVO();
            BeanUtils.copyProperties(tree, treeStructureVO);
            return treeStructureVO;
        }).collect(Collectors.toMap(TreeStructureVO::getTreeId, a -> a, (k1, k2) -> k1));

        List<TreeStructureVO> treeStructureVOS = new LinkedList<>();
        for (Tree tree : treeList) {
            //当前场景
            TreeStructureVO treeStructureVO = treeStructureVOMap.get(tree.getTreeId());
            //计算在线离线
            Integer total = NumericalConstants.ZERO;
            Integer onlineTotal = NumericalConstants.ZERO;
            Integer offlineTotal = NumericalConstants.ZERO;
            if (!CollectionUtils.isEmpty(locationDeviceMap)) {
                List<LocationDevice> locationDeviceList = locationDeviceMap.get(tree.getTreeId());
                if (!CollectionUtils.isEmpty(locationDeviceList)) {
                    total = locationDeviceList.size();
                    if (!CollectionUtils.isEmpty(tagInfoVOMap)) {
                        for (LocationDevice locationDevice : locationDeviceList) {
                            HttpTagInfoVO httpTagInfoVO = tagInfoVOMap.get(locationDevice.getDeviceName());
                            if (httpTagInfoVO != null && httpTagInfoVO.getOnline()) {
                                onlineTotal++;
                            } else {
                                offlineTotal++;
                            }
                        }
                    }
                }
            }
            treeStructureVO.setTotal(total);
            treeStructureVO.setOnlineTotal(onlineTotal);
            treeStructureVO.setOfflineTotal(offlineTotal);
            //当前场景的父场景
            TreeStructureVO parentTreeStructure = treeStructureVOMap.get(tree.getParentId());
            //不为空说明有上级场景
            if (parentTreeStructure != null) {
                Integer treeId = parentTreeStructure.getTreeId();
                if (CollectionUtils.isEmpty(parentTreeStructure.getChildren())) {
                    List<TreeStructureVO> treeStructureVOList = new LinkedList<>();
                    treeStructureVOList.add(treeStructureVO);
                    parentTreeStructure.setChildren(treeStructureVOList);
                    treeStructureVOMap.put(treeId, parentTreeStructure);
                } else {
                    parentTreeStructure.getChildren().add(treeStructureVO);
                    treeStructureVOMap.put(treeId, parentTreeStructure);
                }
            } else {
                //最上层场景
                if (CollectionUtils.isEmpty(treeStructureVO.getChildren())) {
                    treeStructureVO.setChildren(new LinkedList<>());
                }
                treeStructureVOS.add(treeStructureVO);
            }
        }
        treeStructureVOS.stream().forEach(treeStructureVO -> {
            setTotal(treeStructureVO);
        });
        return treeStructureVOS;
    }

    /**
     * 计算数量
     *
     * @param treeStructureVO
     * @return void
     * @author ljx
     * @time 2024/10/7 14:15
     */
    private void setTotal(TreeStructureVO treeStructureVO) {
        List<TreeStructureVO> children = treeStructureVO.getChildren();
        if (!CollectionUtils.isEmpty(children)) {
            for (TreeStructureVO sonTreeStructure : children) {
                if (!CollectionUtils.isEmpty(sonTreeStructure.getChildren()) && sonTreeStructure.getChildren().size() != 0) {
                    setTotal(sonTreeStructure);
                    treeStructureVO.setTotal(treeStructureVO.getTotal() + sonTreeStructure.getTotal());
                    treeStructureVO.setOnlineTotal(treeStructureVO.getOnlineTotal() + sonTreeStructure.getOnlineTotal());
                    treeStructureVO.setOfflineTotal(treeStructureVO.getOfflineTotal() + sonTreeStructure.getOfflineTotal());
                } else {
                    treeStructureVO.setTotal(treeStructureVO.getTotal() + sonTreeStructure.getTotal());
                    treeStructureVO.setOnlineTotal(treeStructureVO.getOnlineTotal() + sonTreeStructure.getOnlineTotal());
                    treeStructureVO.setOfflineTotal(treeStructureVO.getOfflineTotal() + sonTreeStructure.getOfflineTotal());
                }
            }
        }
    }

    /**
     * 根据身份证号计算年龄
     *
     * @param idCardNo
     * @return java.lang.Integer
     * @author ljx
     * @time 2024/10/21 16:23
     */
    public static Integer getAgeByIdCodeNo(String idCardNo) {
        if (StringUtils.isBlank(idCardNo)) {
            return null;
        }
        String year = idCardNo.substring(6, 10);
        String month = idCardNo.substring(10, 12);
        String day = idCardNo.substring(12, 14);
        String dateOfBirth = year + "-" + month + "-" + day + " 00:00:00";
        return getAgeByDate(dateOfBirth);
    }


}
